package com.wyh.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.wyh.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.wyh.lotterysystem.common.exception.ServiceException;
import com.wyh.lotterysystem.common.utils.*;
import com.wyh.lotterysystem.controller.request.LoginRequest;
import com.wyh.lotterysystem.controller.request.PasswordLoginRequest;
import com.wyh.lotterysystem.controller.request.RegisterRequest;
import com.wyh.lotterysystem.controller.request.VerificationCodeLoginRequest;
import com.wyh.lotterysystem.dao.dataobject.Encrypt;
import com.wyh.lotterysystem.dao.dataobject.UserDo;
import com.wyh.lotterysystem.dao.mapper.UserMapper;
import com.wyh.lotterysystem.service.UserService;
import com.wyh.lotterysystem.service.dto.LoginDTO;
import com.wyh.lotterysystem.service.dto.RegisterDTO;
import com.wyh.lotterysystem.service.dto.UserListDTO;
import com.wyh.lotterysystem.service.enums.UserIdentityEnum;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl implements UserService {


    @Autowired
    UserMapper userMapper;

    @Autowired
    RedisUtil redisUtil;

    private static final String VERIFICATION_CODE_PREFIX = "VERIFICATION_CODE_";
    private static final Long VERIFICATION_CODE_TIMEOUT = 60L;


    @Override
    public RegisterDTO register(RegisterRequest request) {
        //校验参数是否合法
        checkRegisterRequest(request);

        //构造dao层参数(加密)
        UserDo userDo = new UserDo();
        userDo.setUserName(request.getName());
        userDo.setEmail(request.getMail());
        userDo.setIdentity(request.getIdentity());
        userDo.setPhoneNumber(new Encrypt(request.getPhoneNumber()));
        //先判断是否有密码，没有就不需要加密
        if (StringUtils.hasText(request.getPassword())){
            userDo.setPassword(DigestUtil.sha256Hex(request.getPassword().getBytes(StandardCharsets.UTF_8)));
        }

        //调用dao层接口
        userMapper.insertUser(userDo);

        //构造返回值
        RegisterDTO registerDTO = new RegisterDTO();
        registerDTO.setId(userDo.getId());

        //返回给controller层数据
        return registerDTO;
    }

    /**
     * 校验请求中的数据
     * @param request 注册对象
     */
    private void checkRegisterRequest(RegisterRequest request) {
        //request是否为空
        if(null == request){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }

        //邮箱格式
        if (!RegexUtil.checkMail(request.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_EMAIL_IS_MISTAKE);
        }

        //手机号格式
        if (!RegexUtil.checkMobile(request.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_PHONE_IS_MISTAKE);
        }

        //邮箱是否被使用
        if (!isEmailUsed(request.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_EMAIL_IS_USED);
        }

        //手机号是否被使用
        if (!isPhoneUsed(request.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_PHONE_IS_USED);
        }

        //校验身份是否合法
        if (null == UserIdentityEnum.forName(request.getIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_IDENTITY_MISTAKE);
        }

        //如果是管理员的话密码的格式
        if (StringUtils.hasText(request.getPassword())
                && !RegexUtil.checkPassword(request.getPassword()))        {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_PASSWORD_MISTAKE);
        }

    }

    /**
     * 校验手机号是否重复
     * @param phoneNumber
     * @return
     */
    private boolean isPhoneUsed(String phoneNumber) {
        Integer integer = userMapper.countOfPhoneNumber(new Encrypt(phoneNumber));
        return integer == 0;
    }

    /**
     * 校验邮箱是否重复
     * @param email
     * @return
     */
    private boolean isEmailUsed(String email) {
        Integer integer = userMapper.countOfEmail(email);
        return integer == 0;
    }

    /**
     * 发送验证码并校验
     */
    @Override
    public boolean sendEmail(String to, String content) {
        //校验邮箱是否合法
        if (!RegexUtil.checkMail(to)){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_EMAIL_IS_MISTAKE);
        }

        //生成并发送验证码
        String captcha = ICaptchaUtil.getCaptcha(4);
        SendMailUtil.sendEmailCode(to,captcha);

        //用redis保存
//        redisUtil.setRedisAndTime();
        return false;
    }

    /**
     * 用户登录
     * @param request
     * @return
     */
    @Override
    public LoginDTO userLogin(LoginRequest request) {

        LoginDTO loginDTO = new LoginDTO();

        if (request instanceof PasswordLoginRequest){
            loginDTO = checkPasswordLoginRequest((PasswordLoginRequest) request);
        }else if (request instanceof VerificationCodeLoginRequest){
            loginDTO = checkVerificationCodeLoginRequest((VerificationCodeLoginRequest) request);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.USER_NOT_EXIST);
        }

        return loginDTO;
    }

    /**
     * 发送验证码
     * @param email
     */
    @Override
    public void sendVerificationCode(String email) {
        //校验邮箱
        if (!RegexUtil.checkMail(email)){
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_EMAIL_ERROR);
        }

        //生成验证码
        String captcha = ICaptchaUtil.getCaptcha(4);

        //发送验证码
        SendMailUtil.sendEmailCode(email, captcha);

        //缓存
        redisUtil.setRedisAndTime(VERIFICATION_CODE_PREFIX + email,captcha,VERIFICATION_CODE_TIMEOUT);
    }

    /**
     * 根据身份信息获取成员列表
     * @param identity 身份信息
     * @return 成员列表
     */
    @Override
    public List<UserListDTO> findUserList(String identity) {
        //判断身份信息，如果是NORMAL就只返回身份为NORMAL的成员列表，
        //如果是ADMIN就只返回身份为ADMIN的成员列表，
        //如果身份信息为空就返回所有身份的成员列表
        String s = identity == null ? null : UserIdentityEnum.forName(identity).name();

        //查找
        List<UserDo> userDo = userMapper.getUserList(s);

        //转换
        List<UserListDTO> userListDTOS = userDo.stream().map(userDo1 -> {
            UserListDTO userListDTO = new UserListDTO();
            BeanUtils.copyProperties(userDo1,userListDTO);
            userListDTO.setUserId(userDo1.getId());
            return userListDTO;
        }).toList();

        return userListDTOS;
    }

    /**
     * 验证码登录
     * @param request
     */
    private LoginDTO checkVerificationCodeLoginRequest(VerificationCodeLoginRequest request) {
        UserDo userDo = null;

        //校验邮箱格式
        if (!RegexUtil.checkMail(request.getLoginMobile())){
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_EMAIL_ERROR);
        }

        //从数据库中获取对象
        userDo = userMapper.getUserByMail(request.getLoginMobile());

        //校验是否有该对象
        if (null == userDo){
            throw new ServiceException(ServiceErrorCodeConstants.USER_NOT_EXIST);
        }else if (!StringUtils.hasText(request.getMandatoryIdentity()) ||
                !request.getMandatoryIdentity().equalsIgnoreCase(userDo.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_IDENTITY_MISTAKE);
        }

        //校验验证码
        String value = redisUtil.getValue(VERIFICATION_CODE_PREFIX + request.getLoginMobile());
        if (!value.equalsIgnoreCase(request.getVerificationCode())){
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_CODE_ERROR);
        }

        //生成令牌
        Map<String,Object> claims = new HashMap<>();
        claims.put("id",userDo.getId());
        claims.put("identity",userDo.getIdentity());
        String token = JWTUtil.getToken(claims);

        //构造返回值
        LoginDTO loginDTO = new LoginDTO();
        loginDTO.setIdentity(request.getMandatoryIdentity());
        loginDTO.setToken(token);

        //返回
        return loginDTO;
    }

    /**
     * 密码登录
     * @param request
     * @return
     */
    private LoginDTO checkPasswordLoginRequest(PasswordLoginRequest request) {
        UserDo userDo = null;

        if (RegexUtil.checkMail(request.getLoginName())){
            userDo = userMapper.getUserByMail(request.getLoginName());
        }else if (RegexUtil.checkMobile(request.getLoginName())){
            userDo = userMapper.getUserByPhone(new Encrypt(request.getLoginName()));
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.USER_NOT_EXIST);
        }

        if (null == userDo){
            throw new ServiceException(ServiceErrorCodeConstants.USER_NOT_EXIST);
        }else if (!StringUtils.hasText(request.getMandatoryIdentity()) ||
                !request.getMandatoryIdentity().equalsIgnoreCase(userDo.getIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_IDENTITY_MISTAKE);
        }else if (!DigestUtil.sha256Hex(request.getPassword()).equals(userDo.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_PASSWORD_ERROR);
        }

        Map<String,Object> claims = new HashMap<>();
        claims.put("id",userDo.getId());
        claims.put("identity", userDo.getIdentity());
        String token = JWTUtil.getToken(claims);
        LoginDTO loginDTO = new LoginDTO();
        loginDTO.setToken(token);
        loginDTO.setIdentity(userDo.getIdentity());

        return loginDTO;
    }
}
